/**
 * Cesium 工具
 */
const CesiumUtils = {
    /**
     * 初始化地图
     * @param id 地图容器id
     * @param imageryProviderUrl 地图图像地址
     * @param terrainProviderUrl 地图地形地址
     * @returns {module:cesium.Viewer}
     */
    initMap(id,imageryProviderUrl,terrainProviderUrl){
        return new Cesium.Viewer(id, {
            geocoder: true, // 是否显示地名查找控件 （查找位置工具，查找到之后会将镜头对准找到的地址，默认使用bing地图）
            homeButton: true, // 是否显示视角返回初始位置控件
            sceneModePicker: true, // 是否显示投影方式控件（选择视角的模式，有三种:3D，2D，哥伦布视图(CV)）
            baseLayerPicker: true, // 是否显示图层选择控件（图层选择器，选择要显示的地图服务和地形服务）
            navigationHelpButton: true, // 是否显示帮助信息控件（导航帮助按钮，显示默认的地图控制帮助）
            animation: true, // 是否显示动画控件（动画器件，控制视图动画的播放速度）
            timeline: true, // 是否显示时间线控件（时间线,指示当前时间，并允许用户跳到特定的时间）
            fullscreenButton: true, // 是否显示全屏按钮
            vrButton: true, // 是否显示vr按钮
            infoBox: true, // 是否显示点击要素之后显示的信息
            selectionIndicator: true, // 选择指示器
            // creditContainer:"credit", // 版权显示容器

            // 图像提供者
            imageryProvider: new Cesium.WebMapTileServiceImageryProvider({
                url: imageryProviderUrl,
                layer: "tdtBasicLayer",
                style: "default",
                format: "image/jpeg",
                tileMatrixSetID: "GoogleMapsCompatible",
                show: false,
                requestRenderMode: true,
                maximumRenderTimeChange: Infinity
            }),
            // 地形提供者
            terrainProvider: new Cesium.CesiumTerrainProvider({
                url: terrainProviderUrl,
                requestWaterMask: true,
                requestVertexNormals: true
            })
        })
    },

    /**
     * 隐藏版权显示
     * @param viewer
     */
    creditContainerShadowHide(viewer){
        viewer._cesiumWidget._creditContainer.style.display = "none";
    },

    /**
     * 显示帧速
     * @param viewer
     */
    debugShowFramesPerSecond(viewer){
        viewer.scene.debugShowFramesPerSecond = true;
    },

    /**
     * 调整角度
     * @param viewer
     * @param longitude 经度
     * @param latitude 纬度
     * @param height 高度
     * @param heading
     * @param pitch
     * @param roll
     */
    flyTo(viewer,longitude, latitude, height,heading,pitch,roll){
        if (!height) {
            height = 500000
        }
        if (!heading) {
            heading = 0.0
        }
        if (!pitch) {
            pitch = -45
        }
        if (!roll) {
            roll = 0.0
        }
        viewer.camera.flyTo({
            // 设置目的地和高度
            destination: Cesium.Cartesian3.fromDegrees(longitude, latitude, height),
            // 调整方向
            orientation: {
                // 航向(方位角)
                heading: Cesium.Math.toRadians(heading),
                // 变桨(垂直斜角)
                pitch: Cesium.Math.toRadians(pitch),
                // 横滚
                roll: roll
            }
        });
    },

    /**
     * 监听相机移动开始事件
     * @param viewer
     * @param callback
     */
    moveStartEventListener(viewer,callback){
        viewer.camera.moveStart.addEventListener(function(movement) {
            // 在移动开始时记录当前相机高度
            const lastHeight = viewer.camera.positionCartographic.height;
            console.log(lastHeight);
            if (callback) {
                callback(movement);
            }
        });
    },

    /**
     * 监听相机移动结束事件
     * @param viewer
     * @param callback
     */
    moveEndEventListener(viewer,callback){
        viewer.camera.moveEnd.addEventListener(function(movement) {
            console.log('相机结束移动');
            if (callback) {
                callback(movement);
            }
        });
    },

    /**
     * 监听相机移动中事件
     * @param viewer
     * @param callback
     */
    moveEventListener(viewer,callback){
        viewer.camera.move.addEventListener(function(movement) {
            const currentPosition = viewer.camera.position;
            const distanceChange = currentPosition.minus(previousPosition).magnitude();

            if (distanceChange > 0) {
                // 相机向前移动，即放大操作
                console.log('Zoom in');
            } else if (distanceChange < 0) {
                // 相机向后移动，即缩小操作
                console.log('Zoom out');
            }

            if (callback) {
                callback(movement);
            }
        });
    },

    /**
     * 相机缩小事件
     * @param viewer
     * @param callback
     */
    zoomInEventListener(viewer,callback){
        viewer.camera.zoomIn.addEventListener(function() {
            console.log('相机缩小');
            if (callback) {
                callback();
            }
        });
    },

    /**
     * 相机放大事件
     * @param viewer
     * @param callback
     */
    zoomOutEventListener(viewer,callback){
        viewer.camera.zoomOut.addEventListener(function() {
            console.log('相机放大');
            if (callback) {
                callback();
            }
        });
    },

    /**
     * 添加图层
     * @param viewer
     * @param url
     * @param params
     * @param zIndex
     * @param callback
     * @returns {ImageryLayer|null}
     */
    addWmsLayer: function (viewer, url, params, zIndex, callback) {
        if (!viewer) {
            console.log('no viewer found!');
            return null;
        }
        if (!params || !params.layerName) {
            console.log('no layerName found!');
            return null;
        }
        const parameters = {service: 'WMS', format: 'image/png', transparent: true};
        if (params.styles) {
            parameters.styles = params.styles;
        }
        if (params.cql_filter) {
            parameters.cql_filter = params.cql_filter;
        }
        const addLayer = new Cesium.WebMapServiceImageryProvider({
            url: url,
            layers: params.layerName,
            parameters: parameters
        });
        let layer;
        if (zIndex) {
            layer = viewer.imageryLayers.addImageryProvider(addLayer, zIndex);
        } else {
            layer = viewer.imageryLayers.addImageryProvider(addLayer);
        }
        if (callback) {
            callback(layer);
        }
        return layer;
    },

    /**
     * 添加图片图层
     * @param viewer
     * @param imgUrl
     * @param rectangle
     * @param alpha
     * @returns {ImageryLayer|null}
     */
    addImageLayer: function (viewer, imgUrl, rectangle, alpha) {
        if (!viewer || !imgUrl) {
            console.log('no found params!');
            return null;
        }
        if (!validateImgUrl(imgUrl)) {
            console.log(imgUrl);
            console.log('imgUrl 404!');
            return null;
        }
        const layer = viewer.imageryLayers.addImageryProvider(
            new Cesium.SingleTileImageryProvider({
                url: imgUrl,
                rectangle: rectangle
            })
        );
        if (alpha && alpha <= 1) {
            layer.alpha = alpha;
        }
        return layer;
    },

    /**
     * 添加实体 gltf
     * @param viewer
     * @param longitude 左下经度
     * @param latitude 左下纬度
     * @param height 高度
     * @param uri 实体地址
     * @param color 渲染颜色 格式: Cesium.Color.fromBytes(251, 243, 100, 128)
     * @param show 是否显示
     * @param name 实体名称，自定义可以不填
     * @returns {Entity}
     */
    addEntities(viewer,longitude,latitude,height,uri,color,show,name){
        const entity = {
            position: Cesium.Cartesian3.fromDegrees(longitude, latitude, height),
            model: {
                uri: uri,
                color: color
            },
        }
        if (show) {
            entity.show = show;
        }
        if (name) {
            entity.name = name;
        }

        return viewer.entities.add(entity)
    },
    
    /**
     * 绘制矩形框
     * @param viewer
     * @param lowerLeftLon  左下
     * @param lowerLeftLat
     * @param topRightLon 右上
     * @param topRightLat
     * @param bottomHeight 底高 (单位：米)
     * @param topHeight  顶高 (单位：米)
     * @returns {Entity}
     */
    drawRectangle(viewer,lowerLeftLon,lowerLeftLat,topRightLon,topRightLat,bottomHeight,topHeight){
        const coordRect = {
            leftBottom: {// 左下
                lon: lowerLeftLon,
                lat: lowerLeftLat
            },
            leftTop: {// 左上
                lon: lowerLeftLon,
                lat: topRightLat
            },
            rightBottom: {// 右下
                lon: topRightLon,
                lat: lowerLeftLat
            },
            rightTop: {// 右上
                lon: topRightLon,
                lat: topRightLat
            }
        };
        return viewer.entities.add({
            wall : {
                positions : Cesium.Cartesian3.fromDegreesArrayHeights([
                    coordRect.leftBottom.lon, coordRect.leftBottom.lat, topHeight,
                    coordRect.rightBottom.lon, coordRect.rightBottom.lat, topHeight,
                    coordRect.rightTop.lon, coordRect.rightTop.lat, topHeight,
                    coordRect.leftTop.lon, coordRect.leftTop.lat, topHeight,
                    coordRect.leftBottom.lon, coordRect.leftBottom.lat, topHeight
                ]),
                material : Cesium.Color.WHITE.withAlpha(0.1),
                minimumHeights: [bottomHeight, bottomHeight, bottomHeight, bottomHeight, bottomHeight],
                outline : true,
                outlineColor : Cesium.Color.WHITE
            }
        })
    },

    /**
     * 绘制墙
     * @param viewer
     * @param positions
     * @param imgUrl
     * @returns {Entity}
     */
    drawWall(viewer,positions,imgUrl){
        let material;
        if (imgUrl) {
            material = new Cesium.ImageMaterialProperty({
                image: imgUrl,
                transparent: true,
                color : new Cesium.Color(1.0, 1.0, 1.0, 0.5) // 设置全局透明度为半透明
            })
        }else {
            material = Cesium.Color.WHITE.withAlpha(0.1)
        }
        return viewer.entities.add({
            wall: {
                positions: Cesium.Cartesian3.fromDegreesArrayHeights(positions),
                material: material,
                outline: true,
                outlineColor: Cesium.Color.LIGHTGRAY,
                outlineWidth: 1
            }
        })
    },

    /**
     * 绘制文字 - 单个
     * @param viewer
     * @param lon
     * @param lat
     * @param height
     * @param text
     * @returns {any}
     */
    drawText(viewer,lon,lat,height,text){
        const primitives = viewer.scene.primitives.add(new Cesium.LabelCollection())
        primitives.add({
            position : Cesium.Cartesian3.fromDegrees(lon,lat,height),
            font : '14px Helvetica',
            outlineColor : Cesium.Color.BLACK,
            fillColor : Cesium.Color.WHITE,
            text : text
        })
        return primitives
    },

    /**
     * 绘制文字 - 数组
     * @param viewer
     * @param textArray
     * @returns {any}
     */
    drawTextArray(viewer,textArray){
        const primitives = viewer.scene.primitives.add(new Cesium.LabelCollection())
        for (let obj of textArray) {
            primitives.add({
                position : Cesium.Cartesian3.fromDegrees(obj[0],obj[1],obj[2]),
                font : '14px Helvetica',
                outlineColor : Cesium.Color.BLACK,
                fillColor : Cesium.Color.RED,
                text : obj[3]
            })
        }
        return primitives
    },

    /**
     * 移除对象
     * @param viewer
     * @param layer
     * @returns {boolean}
     */
    removeLayer: function (viewer, layer) {
        if (!viewer) {
            console.log('no viewer found!');
            return false;
        }
        if (!layer) {
            console.log('no found Layer');
            return false;
        }
        // 判断图层是否存在
        if (viewer.imageryLayers.contains(layer)) {
            return viewer.imageryLayers.remove(layer, true);
        }
        // 判断实体是否存在
        if (viewer.entities.contains(layer)) {
            return viewer.entities.remove(layer);
        }
        console.log('no found Layer');
        return false;
    },

}

/**
 * 验证图片链接
 * @param url
 * @returns {boolean}
 */
function validateImgUrl(url){
    let flag = false;
    try {
        let xmlHttp;
        if (window.ActiveXObject) {
            xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
        } else if (window.XMLHttpRequest) {
            xmlHttp = new XMLHttpRequest();
        }
        xmlHttp.open("Get", url, false);
        xmlHttp.send();
        flag = (xmlHttp.status !== 404);
    } catch (e) {
        console.log(e);
    }
    return flag;
}